gusucode.com > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序 > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序/code/Src/Client/scwinlib/SCMemDC.cpp

    //Download by http://www.NewXing.com
/*
*	This file is part of the EMFexplorer projet.
*	Copyright (C) 2004 Smith Charles.
*
*	This library is free software; you can redistribute it and/or
*	modify it under the terms of the GNU Lesser General Public
*	License as published by the Free Software Foundation; either
*	version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
*
*	Extension: for commercial use, apply the Equity Public License, which
*	adds to the normal terms of the GLPL a condition of donation to the author.
*   If you are interested in support for this source code,
*   contact Smith Charles <smith.charles@free.fr> for more information.
*/

#include "stdafx.h"
#include "SCMemDC.h"
#include "SCBitmap.h"
#include "SCPalette.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSCMemDC::CSCMemDC():
	CDC(),
	m_hStockBM(NULL),
	m_pBmpMem(NULL),
	m_pPal(NULL),
	m_iWidth(32),
	m_iHeight(32),
	m_InitColor(RGB(255,255,255)),
	m_iGrayScale(STGRAY_SCALE_NONE),
	m_iGrMode(0)
{
}

CSCMemDC::~CSCMemDC()
{
	// Clean up
	SCCleanUp();

	// delete Windows DC
	this->DeleteDC();
}

void CSCMemDC::SCCleanUp()
{
	// restore and delete palette
	if (m_pPal)
	{
		// reselect the stock palette
		::SelectObject(m_hDC, GetStockObject(DEFAULT_PALETTE));
		// delete the palette
		m_pPal->DeleteObject();
		delete m_pPal;
		m_pPal = NULL;
	}

	// restore and delete bitmap
	if (m_pBmpMem)
	{
		// reselect the monochrome stock bitmap
		ASSERT(m_hStockBM);
		::SelectObject(m_hDC, m_hStockBM);
		// now we can delete the bitmap
		m_pBmpMem->DeleteObject();
		delete m_pBmpMem;
		m_pBmpMem = NULL;
	}
}

CBitmap *CSCMemDC::SCDetachDIB()
{ 
	CBitmap *pBmp = m_pBmpMem;
	m_pBmpMem = NULL;
	if (m_hStockBM)
	{
		::SelectObject(m_hDC, m_hStockBM);
		m_hStockBM = NULL;
	}
	return pBmp;
}

BOOL CSCMemDC::SCPrepareSurface(int width, int height, HENHMETAFILE hemf/*=NULL*/,
								COLORREF crBkColor/*=RGB(255, 255, 255)*/)
{
	SCCleanUp();
	m_iWidth = width;
	m_iHeight = height;
	// Create an output compatible DC
	//
	if (!m_hDC)
	if (!CreateCompatibleDC(NULL))
		return FALSE;

	// Use screen DC as compatible output device
	HBITMAP hbm = NULL;
	HPALETTE hPalette = NULL;
	if (m_iGrayScale)
		hbm = SCCreateGrayScaleDIBSection(NULL, m_iWidth, m_iHeight, m_iGrayScale);
	else
	{
		hbm = SCCreate24BPPDIBSection(NULL, m_iWidth, m_iHeight);
		if (hemf)
			hPalette = SCGetEMFPalette(hemf);
		//else
		//	hPalette = SCGetSystemPalette();
	}

	if (!hbm)
	{
		return FALSE;
	}
	m_pBmpMem = new CBitmap;
	m_pBmpMem->Attach(hbm);
	// Select the bitmap into the off-screen DC.
	//
	// Do not use MFC. MFC would return a temporary object linked to the stock bitmap
	// m_pBmOld = this->SelectObject(m_pBmpMem);	  // no!
	// Instead: obtain the stock monochrome bitmap from GDI and save it, as we cant use
	// GetStockObject for this bitmap.
	m_hStockBM = (HBITMAP)::SelectObject(m_hDC, hbm);
	ASSERT(m_hStockBM); // if NULL, GDI failed (maybe memory is low)

	// Palette management
	if (hPalette)
	{
		m_pPal = new CPalette;
		m_pPal->Attach(hPalette);
		CPalette* pPalOld = this->SelectPalette(m_pPal, TRUE); // pPalOld is temporary
		if (pPalOld)
		{
			if (GDI_ERROR == this->RealizePalette())
			{// Error management ?
				// We can grab something (not too pretty) without palette
				
			}
		}
		// Error management ?
		// We can grab something (not too pretty) without palette
	}

	// Erase the background.
	//
	m_InitColor = crBkColor;
	return SCEraseBkgn();
}

BOOL CSCMemDC::SCShrinkSurface(CRect rc)
{
	// Create an output compatible DC
	//
	CDC tmpDC;
	if (!tmpDC.CreateCompatibleDC(NULL))
		return FALSE;

	// Use screen DC as compatible output device
	HBITMAP hbm = NULL;
	HPALETTE hPalette = NULL;
	if (m_iGrayScale)
		hbm = SCCreateGrayScaleDIBSection(NULL, rc.Width(), rc.Height(), m_iGrayScale);
	else
	{
		hbm = SCCreate24BPPDIBSection(NULL, rc.Width(), rc.Height());
	}

	if (!hbm)
		return FALSE;

	CBitmap* pBmp = new CBitmap;
	pBmp->Attach(hbm);
	// Select the bitmap into the off-screen DC and init tmp surface.
	//
	CBitmap* pBmOld = tmpDC.SelectObject(pBmp);
	tmpDC.BitBlt(0, 0, rc.Width(), rc.Height(), this, rc.left, rc.top, SRCCOPY);
	tmpDC.SelectObject(pBmOld);

	// Swap surfaces
	this->SelectObject(pBmp); // select new bmp
	// delete the old one
	if (m_pBmpMem)
	{
		m_pBmpMem->DeleteObject();
		delete m_pBmpMem;
	}
	m_pBmpMem = pBmp;

	// new surface size
	m_iWidth = rc.Width();
	m_iHeight = rc.Height();
	return TRUE;
}

BOOL CSCMemDC::SCResetSurfaceColor(int iColor)
{
	if (m_InitColor == iColor)
		return TRUE;

	m_InitColor = iColor;
	return SCEraseBkgn();
}

BOOL CSCMemDC::SCEraseBkgn()
{
	CBrush brush;
	CRect rc(0, 0, m_iWidth, m_iHeight);
	brush.CreateSolidBrush(m_InitColor);
	DPtoLP(&rc);
	FillRect(&rc, &brush);
	return TRUE;
}

BOOL CSCMemDC::SCEraseBkgn(CBrush* pBrush)
{
	ASSERT(pBrush);
	CRect rc(0, 0, m_iWidth, m_iHeight);
	DPtoLP(&rc);
	FillRect(&rc, pBrush);
	return TRUE;
}

///
/// Rotate and translate DC so that the origin is at (rect.left, rect.top)
///
BOOL CSCMemDC::SCRotateDC(int iAngle, CRect rect, int iXPos, int iYPos)
{
	return ::SCRotateDC(m_hDC, iAngle, rect, iXPos, iYPos, m_iGrMode);
}

///
/// Translate DC so that the origin return at (0, 0) after it was set at (rect.left, rect.top)
///
BOOL CSCMemDC::SCRestoreOrigin(int iAngle, CRect rect, int iXPos, int iYPos)
{
	XFORM xform;
	memset(&xform, 0, sizeof(xform));
	xform.eM11 = 1;
	xform.eM22 = 1;
	switch (iAngle)
	{
	case 90:
		xform.eDx = (float)(-rect.top + iXPos);
		xform.eDy = (float)(rect.left + iYPos);
		break;

	case 270:
		xform.eDx = (float)(rect.top + iXPos);
		xform.eDy = (float)(-rect.left + iYPos);
		break;

	case 180:
		xform.eDx = (float)(-rect.left + iXPos);
		xform.eDy = (float)(-rect.top + iYPos);
		break;

	case 0:
		xform.eDx = (float)(rect.left + iXPos);
		xform.eDy = (float)(rect.top + iYPos);
		break;

	default:
		ASSERT(0);
	}
	BOOL bOk = ModifyWorldTransform(m_hDC, &xform, MWT_RIGHTMULTIPLY);
	ASSERT(bOk);

	return bOk;
}

BOOL CSCMemDC::SCSelfRotate(int iAngle, CSize sizeDelta)
{
	m_iGrMode = SetGraphicsMode(m_hDC, GM_ADVANCED);
	ASSERT(m_iGrMode);
	if (!m_iGrMode)
		return FALSE;

	BOOL bOk = FALSE;
	XFORM xform;
	memset(&xform, 0, sizeof(xform));
	// Save xform
	XFORM xformSvd;
	bOk = GetWorldTransform(m_hDC, &xformSvd);
	ASSERT(bOk);

	/* translate back to the origin. */
	xform.eM11 =
    xform.eM22 = (float) 1.0;
	SetWorldTransform (m_hDC, &xform);

	// rotate
	switch (iAngle)
	{
	case 90:
		xform.eM11 = 0;
		xform.eM12 = 1;
		xform.eDx = (float)(sizeDelta.cy);
		break;
	case 270:
		xform.eM11 = 0;
		xform.eM12 = -1;
		xform.eDy = (float)(m_iWidth);
		break;
	case 180:
		xform.eM11 = -1;
		xform.eM12 = 0;
		xform.eDy = (float)m_iHeight;
		xform.eDx = (float)m_iWidth;
		break;
	case 0:
		xform.eM11 = 1;
		xform.eM12 = 0;
		break;
	default:
		ASSERT(0);
	}
	xform.eM22 = xform.eM11;
	xform.eM21 = -xform.eM12;
	bOk=ModifyWorldTransform(m_hDC, &xform, MWT_RIGHTMULTIPLY);
	ASSERT(bOk);

	/* translate back to the original offset. */
	xform.eM11 =
    xform.eM22 = (float) 1.0;
	xform.eM12 =
    xform.eM21 = (float) 0.0;
	
	xform.eDx = xformSvd.eDx;
	xform.eDy = xformSvd.eDy;
	ModifyWorldTransform (m_hDC, &xform, MWT_RIGHTMULTIPLY);
	return bOk;
}

BOOL CSCMemDC::SCUnRotateDC()
{
	return ::SCUnRotateDC(m_hDC, m_iGrMode);
}

////////////////////////////////////////////////////////////////////////////////////
/// Static
///

/// Rotate and translate DC so that the origin is at (rect.left, rect.top)
///
BOOL SCRotateDC(HDC hDC, int iAngle, CRect rect, int iXPos, int iYPos, int& iGrOldMode)
{
	iGrOldMode = SetGraphicsMode(hDC, GM_ADVANCED);
	ASSERT(iGrOldMode);
	if (!iGrOldMode)
		return FALSE;

	BOOL bOk = FALSE;
	XFORM xform;
	memset(&xform, 0, sizeof(xform));

	// Formulas:	
	//xform.eM11 = (float)cos((float)iAngle*(ST_PI)/180.0f); => 0 for PI/2 and 3PI/2, 1 for 0 and PI
	//xform.eM12 = (float)sin((float)iAngle*(ST_PI)/180.0f); => 0 for 0 and PI, 1 for PI/2 and 3PI/2

	// rotate and translate at once
	switch (iAngle)
	{
	case 90:
		xform.eM11 = 0;
		xform.eM12 = 1;
		xform.eDx = (float)(rect.bottom + iXPos);
		xform.eDy = (float)(-rect.left + iYPos);
		break;

	case 270:
		xform.eM11 = 0;
		xform.eM12 = -1;
		xform.eDx = (float)(-rect.top + iXPos);
		xform.eDy = (float)(rect.right + iYPos);
		break;

	case 180:
		xform.eM11 = -1;
		xform.eM12 = 0;
		xform.eDx = (float)(rect.right + iXPos);
		xform.eDy = (float)(rect.bottom + iYPos);
		break;

	case 0:
		xform.eM11 = 1;
		xform.eM12 = 0;
		xform.eDx = (float)(-rect.left + iXPos);
		xform.eDy = (float)(-rect.top + iYPos);
		break;

	default:
		ASSERT(0);
	}
	xform.eM22 = xform.eM11;
	xform.eM21 = -xform.eM12;
	bOk=SetWorldTransform(hDC, &xform);
	ASSERT(bOk);

	return bOk;
}

BOOL SCUnRotateDC(HDC hDC, int iGrOldMode)
{
	if (!iGrOldMode)
		return FALSE;

	BOOL bOk = ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
	ASSERT(bOk);
	int iGrMode = SetGraphicsMode(hDC, iGrOldMode);
	ASSERT(iGrMode);
	return bOk;
}

HDC SCGetAttribDC(HDC hDC)
{
	ASSERT(hDC);
	CDC* pDC = CDC::FromHandle(hDC);
	return pDC->m_hAttribDC;
}
////////////////////////////////////////////////////////////////////////////////////